import { getSafeName } from "./utils";
import { rootStore, Store } from "./store";

/**
 * 
 * @param injectTarget classType or token which will find a inject value
 * @param store store in which will get injected value, default is rootStore
 */
  
export function Inject(injectTarget: any, store?: Store) {

	const safeStore = store || rootStore;
	const targetValue = safeStore.get(injectTarget);
	
	if (targetValue === null) {
		throw new Error("No such value has been provided");
	}

	return (target: any, propertyKey: string, paramterIndex: number) => {
		if (!target.__injectedData) {
			target.__injectedData = [];
		}
		target.__injectedData[paramterIndex] = targetValue;
	};
}

/**
 * 
 * @param target target class which will be injected all dependencies
 * @param params params for constructor function
 */
export function AutoInject<T>(
	target: new (...args: any[]) => T,
	...params: any[]
): T {

	const getConstructor = (target: any) => {
		if (target.prototype && target.prototype.constructor) {
			return target.prototype.constructor;
		} else if (target.constructor) {
			return target.constructor;
		}
		return target;
	};

	const getInjectedData = (target: any) => {
		if (target.__injectedData) {
			return target.__injectedData;
		} else if (target.prototype && target.prototype.__injectedData) {
			return target.__injectedData;
		} else if (
			target.prototype &&
			target.prototype.constructor &&
			target.prototype.constructor.__injectedData
		) {
			return target.prototype.constructor.__injectedData;
		}

		return null;
	};

	const targetCons = getConstructor(target);
	const injectedData = getInjectedData(target);

	if (injectedData === null) {
		return new targetCons(...params);
	}

	return new targetCons(
		...injectedData,
		...params
	);
}
